package mornd.test2;

import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.SmartInitializingSingleton;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationEvent;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.context.ApplicationListener;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.stereotype.Component;

import java.lang.reflect.Method;
import java.util.Map;

/**
 * @author: mornd
 * @dateTime: 2023/5/13 - 16:09
 * 自定义注解实现监听器
 */

@Slf4j
@ComponentScan
public class App {
    public static void main(String[] args) {
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(App.class);
        MyService bean = context.getBean(MyService.class);
        bean.doBusiness();
        context.close();


    }

    // 注册自定义注解实现的监听器
    // SmartInitializingSingleton 接口会在 spring 单例对象创建完成后回调
    @Bean
    public SmartInitializingSingleton myListenerRegister(AnnotationConfigApplicationContext context) {
        return new SmartInitializingSingleton() {
            @Override
            public void afterSingletonsInstantiated() {
                for (String name : context.getBeanDefinitionNames()) {
                    Object bean = context.getBean(name);
                    for (Method m : bean.getClass().getDeclaredMethods()) {
                        if(m.isAnnotationPresent(MyEventListener.class)) {
                            // 获取方法上的参数
                            Class<?>[] parameterTypes = m.getParameterTypes();
                            if(parameterTypes.length > 0) {
                                ApplicationListener listener1 = event -> {
                                    // event对象的class是否是方法第一个参数类型或是其子类
                                    if(parameterTypes[0].isAssignableFrom(event.getClass())) {
                                        try {
                                            m.invoke(bean, event);
                                        } catch (Exception e) {
                                            throw new RuntimeException(e);
                                        }
                                    }
                                };
                                // 添加事件到容器中
                                context.addApplicationListener(listener1);
                            }
                        }
                    }
                }
            }
        };
    }


    @Component
    static class MyService {

        @Autowired
        private ApplicationEventPublisher publisher;

        public void doBusiness() {
            log.debug("业务代码");
            publisher.publishEvent(new MyEvent("abc"));
        }
    }

    static class MyEvent extends ApplicationEvent {

        public MyEvent(Object source) {
            super(source);
        }
    }

    @Component
    static class MyListener implements ApplicationListener<MyEvent> {
        @Override
        public void onApplicationEvent(MyEvent event) {
            log.debug("开始发送邮件，{}", event.getSource());
        }
    }

    @Component
    static class CustomListener {

        @MyEventListener
        public void doService(MyEvent event) {
            log.debug("开始发送短信，{}", event.getSource());
        }
    }

}
